home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / FTPSERV.C < prev    next >
Text File  |  1993-08-09  |  12KB  |  476 lines

  1. /* FTP Server state machine - see RFC 959 */
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <time.h>
  5. #ifdef    __TURBOC__
  6. #include <io.h>
  7. #include <dir.h>
  8. #endif
  9. #include "global.h"
  10. #include "mbuf.h"
  11. #include "dirutil.h"
  12. #include "files.h"
  13. #include "ftp.h"
  14. #include "server.h"
  15.  
  16. /* Response messages */
  17. static char binwarn[]     = "100 Warning: type is ASCII and '%s' appears to be binary\n";
  18. static char sending[]     = "150 Opening data connection for %s %s\n";
  19. static char okay[]      = "200 %s command OK\n";
  20. static char banner[]    = "220 %s FTP %s ready at %s";
  21. static char bye[]         = "221 Goodbye!\n";
  22. static char fileok[]    = "226 File %s OK\n";
  23. static char logged[]     = "230 Logged in\n";
  24. static char deleok[]     = "250 File '%s' deleted\n";
  25. static char pwdmsg[]     = "257 '%s' is current directory\n";
  26. static char givepass[]     = "331 Enter PASS command\n";
  27. static char noconn[]     = "425 Data connection reset\n";
  28. static char badcmd[]     = "500 Unknown command\n";
  29. static char badsyntax[] = "500 Syntax error\n";
  30. static char unsupp[]     = "500 Unsupported command or option\n";
  31. static char only8[]     = "501 Only logical bytesize 8 supported\n";
  32. static char badtype[]     = "501 Unknown type %s\n";
  33. static char badport[]     = "501 Bad port syntax\n";
  34. /*
  35. static char unimp[]     = "502 Command not yet implemented\n";
  36. */
  37. static char userfirst[] = "503 Login with USER first.\n";
  38. static char notlog[]     = "530 Please log in with USER and PASS\n";
  39. static char delefail[]     = "550 Can't delete %s: %s\n";
  40. static char writerr[]     = "552 Can't write %s: %s\n";
  41. static char nodir[]     = "553 Can't read %s: %s\n";
  42. static char cantmake[]     = "553 Can't create %s: %s\n";
  43. static char nopos[]        = "554 Can't position %s\n";
  44. static char noperm[]     = "550 Permission denied\n";
  45.  
  46.  
  47. static void near
  48. close_ftpconn(struct ftpserv *ftp)
  49. {
  50.     if(ftp->fp != NULLFILE) {
  51.         Fclose(ftp->fp);
  52.     }
  53.     ftp->fp = NULLFILE;
  54.  
  55.     if(ftp->data != -1) {
  56.         close_s(ftp->data);
  57.     }
  58.     ftp->data = -1;
  59. }
  60.  
  61. static int near
  62. setup_ftpconn(struct ftpserv *ftp,char *command)
  63. {
  64.     struct sockaddr_in dport;
  65.  
  66.     usprintf(ftp->control,sending,command,ftp->line);
  67.  
  68.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  69.  
  70.     dport.sin_family = AF_INET;
  71.     dport.sin_addr.s_addr = INADDR_ANY;
  72.     dport.sin_port = IPPORT_FTPD;
  73.  
  74.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  75.  
  76.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1) {
  77.         usputs(ftp->control,noconn);
  78.         return -1;
  79.     }
  80.     return 0;
  81. }
  82.  
  83. static void near
  84. sendit(struct ftpserv *ftp,char *command,int32 offset)
  85. {
  86.     if(setup_ftpconn(ftp,command) != -1) {
  87.         if(fseek(ftp->fp,offset,SEEK_SET))   {      /* restart dk5dc */
  88.             usprintf(ftp->control,nopos,ftp->line);
  89.             close_ftpconn(ftp);
  90.             return;
  91.         }
  92.         if(sendfile(ftp->fp,ftp->data,ftp->type,0) == -1) {
  93.             /* An error occurred on the data connection */
  94.             ftp->states = CLOSED;
  95.             usputs(ftp->control,noconn);
  96.             shutdown(ftp->data,2);            /* Blow away data connection */
  97.             ftp->data = -1;
  98.         } else {
  99.             usprintf(ftp->control,fileok,"sent");
  100.         }
  101.     }
  102.     close_ftpconn(ftp);
  103. }
  104.  
  105. /*-------------------------- FTP Server subcmd -----------------------------*/
  106.  
  107. static void near
  108. cwd_command(struct ftpserv *ftp)
  109. {
  110.     if(access(ftp->line,0) == 0) {
  111.         /* Succeeded, record in control block */
  112.         xfree(ftp->cd);
  113.         ftp->cd = strxdup(ftp->line);
  114.         usprintf(ftp->control,pwdmsg,ftp->cd);
  115.     } else {
  116.         /* Failed, don't change anything */
  117.         usprintf(ftp->control,nodir,ftp->line,sys_errlist[errno]);
  118.     }
  119. }
  120.  
  121. static void near
  122. dele_command(struct ftpserv *ftp)
  123. {
  124.     if(unlink(ftp->line) == 0) {
  125.         usprintf(ftp->control,deleok,ftp->line);
  126.     } else {
  127.         usprintf(ftp->control,delefail,ftp->line,sys_errlist[errno]);
  128.     }
  129. }
  130.  
  131. static void near
  132. dir_command(struct ftpserv *ftp)
  133. {
  134.     if((ftp->fp = dir(ftp->line,1)) == NULLFILE) {
  135.         usprintf(ftp->control,nodir,ftp->line,sys_errlist[errno]);
  136.     } else {
  137.         sendit(ftp,"LIST",0);
  138.     }
  139. }
  140.  
  141. static void near
  142. mkd_command(struct ftpserv *ftp)
  143. {
  144.     if(mkdir(ftp->line) == 0) {
  145.         usprintf(ftp->control,okay,"MKD");
  146.     } else {
  147.         usprintf(ftp->control,cantmake,ftp->line,sys_errlist[errno]);
  148.     }
  149. }
  150.  
  151. static void near
  152. nlst_command(struct ftpserv *ftp)
  153. {
  154.     if((ftp->fp = dir(ftp->line,0)) == NULLFILE) {
  155.         usprintf(ftp->control,nodir,ftp->line,sys_errlist[errno]);
  156.     } else {
  157.         sendit(ftp,"NLST",0);
  158.     }
  159. }
  160.  
  161. static void near
  162. pass_command(struct ftpserv *ftp)
  163. {
  164.     if(ftp->username == NULLCHAR) {
  165.         usputs(ftp->control,userfirst);
  166.     } else {
  167.         if(userlogin(IPPORT_FTP,(void *)ftp,ftp->line) > 0) {
  168.             ftp->cd = strxdup(ftp->path);
  169.         }
  170.         ftp->states = LOG;
  171.  
  172.         log(ftp->control,9983,"FTP  open %s %s",
  173.             ftp->username,ftp->perms ? "" : ftp->line);
  174.         usputs(ftp->control,ftp->perms ? logged : noperm);
  175.     }
  176. }
  177.  
  178. static void near
  179. port_command(struct ftpserv *ftp)
  180. {
  181.     int i;
  182.     int32 n;
  183.     char *arg = ftp->line;
  184.     struct sockaddr_in *sock = &ftp->port;
  185.  
  186.     sock->sin_port = 0;
  187.  
  188.     for(i = 0, n = 0; i < 4; i++) {
  189.         n = atoi(arg) + (n << 8);
  190.         if((arg = strchr(arg,',')) == NULLCHAR) {
  191.             goto error;
  192.         }
  193.         arg++;
  194.     }
  195.     sock->sin_addr.s_addr = n;
  196.  
  197.     n = atoi(arg);
  198.  
  199.     if((arg = strchr(arg,',')) != NULLCHAR) {
  200.         arg++;
  201.         n = atoi(arg) + (n << 8);
  202.         sock->sin_port = n;
  203.  
  204.         usprintf(ftp->control,okay,"PORT");
  205.         return;
  206.     }
  207. error:
  208.     usputs(ftp->control,badport);
  209. }
  210.  
  211. static void near
  212. pwd_command(struct ftpserv *ftp)
  213. {
  214.     usprintf(ftp->control,pwdmsg,ftp->cd);
  215. }
  216.  
  217. static void near
  218. quit_command(struct ftpserv *ftp)
  219. {
  220.     usputs(ftp->control,bye);
  221.     ftp->states = CLOSED;
  222. }
  223.  
  224. static void near
  225. retr_command(struct ftpserv *ftp)
  226. {
  227.     if((ftp->fp = Fopen(ftp->line,
  228.       (ftp->type == ASCII_TYPE) ? READ_TEXT : READ_BINARY,ftp->control,0)) != NULLFILE) {
  229.         if(ftp->type == ASCII_TYPE && isbinary(ftp->fp)) {
  230.             usprintf(ftp->control,binwarn,ftp->line);
  231.         }
  232.         sendit(ftp,"RETR",0);
  233.     }
  234. }
  235.  
  236. static void near
  237. rmd_command(struct ftpserv *ftp)
  238. {
  239.     if(rmdir(ftp->line) == 0) {
  240.         usprintf(ftp->control,deleok,ftp->line);
  241.     } else {
  242.         usprintf(ftp->control,delefail,ftp->line,sys_errlist[errno]);
  243.     }
  244. }
  245.  
  246. static void near
  247. srest_command(struct ftpserv *ftp)
  248. {
  249.     char *cp;
  250.  
  251.     /*---------------------------------------------------------------*
  252.      * Restart request comes in at this point. Try to find 'remote-  *
  253.      * file, check offset.                                           *
  254.      * refuse if pass EOF else advance and initiate transfer         *
  255.      *---------------------------------------------------------------*/
  256.  
  257.     if((cp = strchr(ftp->line,' ')) != NULLCHAR) {
  258.         int32 restpos = atol(cp);
  259.         *cp = '\0';
  260.  
  261.         if((ftp->fp = Fopen(ftp->line,
  262.           (ftp->type == ASCII_TYPE) ? READ_TEXT : READ_BINARY,ftp->control,0)) != NULLFILE) {
  263.             if(ftp->type == ASCII_TYPE && isbinary(ftp->fp)) {
  264.                 usprintf(ftp->control,binwarn,ftp->line);
  265.             }
  266.             sendit(ftp,"SREST",restpos);
  267.         }
  268.     } else {
  269.         usputs(ftp->control,badsyntax);
  270.     }
  271. }
  272.  
  273. static void near
  274. stor_command(struct ftpserv *ftp)
  275. {
  276.     if((ftp->fp = Fopen(ftp->line,
  277.       (ftp->type == ASCII_TYPE) ? WRITE_TEXT : WRITE_BINARY,ftp->control,1)) != NULLFILE) {
  278.         if(setup_ftpconn(ftp,"STOR") != -1) {
  279.             if(recvfile(ftp->fp,ftp->data,ftp->type,0) == -1) {
  280.                 /* An error occurred while writing the file */
  281.                 ftp->states = CLOSED;
  282.                 usprintf(ftp->control,errno ? writerr : noconn,ftp->line,sys_errlist[errno]);
  283.                 shutdown(ftp->data,2);            /* Blow away data connection */
  284.                 ftp->data = -1;
  285.             } else {
  286.                 usprintf(ftp->control,fileok,"received");
  287.             }
  288.         }
  289.         close_ftpconn(ftp);
  290.     }
  291. }
  292.  
  293. static void near
  294. type_command(struct ftpserv *ftp)
  295. {
  296.     int ok = TRUE;
  297.     char *cp = ftp->line;
  298.  
  299.     switch(tolower(*cp)) {
  300.     case 'a':                            /* Ascii */
  301.         ftp->type = ASCII_TYPE;
  302.         break;
  303.     case 'l':
  304.         while(!isspace(*cp++)) ;
  305.         if(*cp != '8') {
  306.             usputs(ftp->control,only8);
  307.             return;
  308.         }
  309.         ftp->type = LOGICAL_TYPE;
  310.         ftp->logbsize = 8;
  311.         break;
  312.     case 'b':                            /* Binary */
  313.     case 'i':                            /* Image */
  314.         ftp->type = IMAGE_TYPE;
  315.         break;
  316.     default:    /* Invalid */
  317.         ok = FALSE;
  318.         break;
  319.     }
  320.     if(ok)
  321.         usprintf(ftp->control,okay,"TYPE");
  322.     else
  323.         usprintf(ftp->control,badtype,strupr(cp));
  324. }
  325.  
  326. static void near
  327. unsupp_command(struct ftpserv *ftp)
  328. {
  329.     usputs(ftp->control,unsupp);
  330. }
  331.  
  332. static void near
  333. user_command(struct ftpserv *ftp)
  334. {
  335.     if(ftp->username != NULLCHAR)
  336.         xfree(ftp->username);
  337.     ftp->username = strxdup(ftp->line);
  338.     ftp->states = PASS;
  339.     usputs(ftp->control,givepass);
  340. }
  341.  
  342. void
  343. ftpserv(int s,void *unused,void *p)
  344. {
  345.     /* Command table */
  346.     static struct cmdtable {
  347.         char *name;
  348.         void near (*fnc)(struct ftpserv *ftp);
  349.         int states;
  350.         int perms;
  351.     } cmdtable[] = {
  352.         {"ACCT",    unsupp_command,    LOG,    0},
  353.         {"CWD",        cwd_command,     LOG,    RETR_CMD},
  354.         {"DELE",    dele_command,    LOG,    DELE_CMD},
  355.         {"HELP",    unsupp_command,    LOG,    0},
  356.         {"LIST",    dir_command,    LOG,    RETR_CMD},
  357.         {"MKD",        mkd_command,     LOG,    MKD_CMD},
  358.         {"MODE",    unsupp_command,    LOG,    0},
  359.         {"NLST",    nlst_command,    LOG,    RETR_CMD},
  360.         {"PASS",    pass_command,    PASS,    0},
  361.         {"PORT",    port_command,    LOG,    0},
  362.         {"PWD",        pwd_command,     LOG,    0},
  363.         {"QUIT",    quit_command,    USER,    0},
  364.         {"RETR",    retr_command,    LOG,    RETR_CMD},
  365.         {"RMD",        rmd_command,     LOG,    RMD_CMD},
  366.         {"SREST",    srest_command,    LOG,    RETR_CMD},
  367.         {"STOR",    stor_command,    LOG,    STOR_CMD},
  368.         {"STRU",    unsupp_command,    LOG,    0},
  369.         {"TYPE",    type_command,    LOG,    0},
  370.         {"USER",    user_command,      USER,    0},
  371.         /* For compatibility with 4.2BSD */
  372.         {"XMKD",    mkd_command,     LOG,    MKD_CMD},
  373.         {"XPWD",    pwd_command,     LOG,    0},
  374.         {"XRMD",    rmd_command,     LOG,    RMD_CMD},
  375.         {0,    0,    0,    0}
  376.     } ;
  377.     struct cmdtable *cmdp;
  378.  
  379.     char *cp, *cp1;
  380.     int arglen, i = SOCKSIZE;
  381.     struct sockaddr_in socket;
  382.     struct ftpserv *ftp;
  383.  
  384.     sockowner(s,Curproc);                /* We own it now */
  385.     sockmode(s,SOCK_ASCII);
  386.  
  387.     usprintf(s,banner,Hostname,Version,ctime(&currtime));
  388.  
  389.     ftp = mxallocw(sizeof(struct ftpserv));
  390.     ftp->line = mxallocw(FTPLINE);
  391.     ftp->data = -1;
  392.     ftp->control = s;
  393.     ftp->type = ASCII_TYPE;
  394.  
  395.     /* Set default data port */
  396.     getpeername(ftp->control,(char *)&socket,&i);
  397.     socket.sin_port = IPPORT_FTPD;
  398.     ASSIGN(ftp->port,socket);
  399.  
  400.     for( ; ;) {
  401. loop:
  402.         if(ftp->states == CLOSED)
  403.             break;
  404.  
  405.         if(recvline(ftp->control,ftp->line,FTPLINE) <= 0) {
  406.             /* He closed on us */
  407.             break;
  408.         }
  409.         rip(ftp->line);
  410.  
  411.         arglen = 0;
  412.         cp = ftp->line;
  413.  
  414.         while(isspace(*cp))
  415.             cp++;
  416.  
  417.         cp1 = cp;
  418.  
  419.         while(*cp1 != '\0' && !isspace(*cp1)) {
  420.             cp1++;
  421.             arglen++;
  422.         }
  423.         if(arglen) {
  424.             for(cmdp = cmdtable; cmdp->name; cmdp++) {
  425.                 if(strnicmp(cmdp->name,cp,arglen) == 0) {
  426.                     char *file, *cp2 = cp1;
  427.  
  428.                     if(cmdp->fnc != port_command) {
  429.                         log(ftp->control,IPPORT_FTP,ftp->line);        /* TEST */
  430.                     }
  431.                     if(ftp->states < cmdp->states) {
  432.                         usputs(ftp->control,notlog);
  433.                         goto loop;
  434.                     }
  435.                     while(isspace(*cp2)) {
  436.                         cp2++;
  437.                     }
  438.                     if(cmdp->perms) {
  439.                         file = pathname(ftp->cd,cp2);
  440.                         if(!permcheck(ftp->path,ftp->perms,cmdp->perms,file)) {
  441.                             usputs(ftp->control,noperm);
  442.                             xfree(file);
  443.                             goto loop;
  444.                         }
  445.                     } else {
  446.                         file = strxdup(cp2);
  447.                     }
  448.                     strcpy(ftp->line,file);
  449.                     xfree(file);
  450.                     (*cmdp->fnc)(ftp);
  451.                     goto loop;
  452.                 }
  453.             }
  454.         }
  455.         /* Can't be a legal FTP command */
  456.         usputs(ftp->control,badcmd);
  457.     }
  458.     log(ftp->control,9983,"FTP  close");
  459.  
  460.     /* Clean up */
  461.     close_ftpconn(ftp);
  462.  
  463.     close_s(ftp->control);
  464.  
  465.     if(ftp->path != NULLCHAR)
  466.         xfree(ftp->path);
  467.  
  468.     if(ftp->cd != NULLCHAR)
  469.         xfree(ftp->cd);
  470.  
  471.     xfree(ftp->username);
  472.     xfree(ftp->line);
  473.     xfree(ftp);
  474. }
  475.  
  476.